#include "sgmexporter.h"

bool IsTCBContol(Control *control)
{
	return 
		control ->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0) ||
		control ->ClassID() == Class_ID(TCBINTERP_POSITION_CLASS_ID,0) ||
		control ->ClassID() == Class_ID(TCBINTERP_ROTATION_CLASS_ID,0) ||
		control ->ClassID() == Class_ID(TCBINTERP_POINT3_CLASS_ID,0) ||
		control ->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID,0);
}

IKey *GetKey(Control *control)
{
	if (control ->ClassID() == Class_ID(TCBINTERP_POSITION_CLASS_ID,0))
		return new ITCBPoint3Key();

	if (control ->ClassID() == Class_ID(TCBINTERP_ROTATION_CLASS_ID,0))
		return new ITCBRotKey();

	if (control ->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID,0))
		return new ITCBScaleKey();

	if (control ->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
		return new ITCBFloatKey();

	return NULL;
}

void GetTimeline(std::set<int> &times, Control *control)
{
	IKeyControl *keyControl = GetKeyControlInterface(control);

	for (int i = 0; i < keyControl ->GetNumKeys(); i++)
	{
		IKey *key = GetKey(control);
		keyControl ->GetKey(i, key);
		times.insert(key ->time);
		delete key;
	}
}

void SGMExporter::ExportAnimation(Control *control, ISaver *saver, bool &hasPos, bool &hasRot, bool &hasScale)
{
	/*Control *pos = control ->GetPositionController();
	Control *rot = control ->GetRotationController();
	Control *scale = control ->GetScaleController();
	Control *roll = control ->GetRollController();

	std::set<int> times;

	if (pos != NULL && IsTCBContol(pos))
	GetTimeline(times, pos);

	if (rot != NULL && IsTCBContol(rot))
	GetTimeline(times, rot);

	if (scale != NULL && IsTCBContol(scale))
	GetTimeline(times, scale);

	if (roll != NULL && IsTCBContol(roll))
	GetTimeline(times, roll);

	std::set<int>::iterator i;

	fh ->writeInt(times.size());
	Log::Get() << "Keys Count: " << times.size() << "\n";

	int keyNumber = 0;

	for (i = times.begin(); i != times.end(); i++)
	{
	Log::Get() << "Key Number: " << keyNumber++ << "\n";
	Interval interval;

	fh ->writeFloat(TicksToSec(*i) * 1000.0f);
	Log::Get() << "Time: " << TicksToSec(*i) * 1000.0f << "\n";

	if (pos != NULL)
	{
	Point3 point3;
	pos ->GetValue((*i), &point3, interval);

	fh ->writeFloat(point3.x);
	fh ->writeFloat(point3.z);
	fh ->writeFloat(-point3.y);
	Log::Get() << "Position: (" << point3.x << ", " << point3.z << ", " << -point3.y << ")\n";
	}
	else
	{
	fh ->writeFloat(0);
	fh ->writeFloat(0);
	fh ->writeFloat(0);
	Log::Get() << "Position: (0, 0, 0)\n";
	}

	if (rot != NULL)
	{
	Quat q;
	rot ->GetValue((*i), &q, interval);
	AngAxis angAxis(q);

	fh ->writeFloat(-angAxis.angle);
	fh ->writeFloat(angAxis.axis.x);
	fh ->writeFloat(angAxis.axis.z);
	fh ->writeFloat(-angAxis.axis.y);
	Log::Get() << "Angle: " << -angAxis.angle << ", Axis: (" << angAxis.axis.x << ", " << angAxis.axis.z << ", " << -angAxis.axis.y << ")\n";
	}
	else
	{
	fh ->writeFloat(0);
	fh ->writeFloat(1);
	fh ->writeFloat(0);
	fh ->writeFloat(0);
	Log::Get() << "Angle: 0, Axis: (1, 0, 0)\n";
	}

	if (scale != NULL)
	{
	ScaleValue scaleVal;
	scale ->GetValue((*i), &scaleVal, interval);

	fh ->writeFloat(scaleVal.s.x);
	fh ->writeFloat(scaleVal.s.z);
	fh ->writeFloat(scaleVal.s.y);
	Log::Get() << "Scale: (" << scaleVal.s.x << ", " << scaleVal.s.z << ", " << scaleVal.s.y << ")\n";
	}
	else
	{
	fh ->writeFloat(1);
	fh ->writeFloat(1);
	fh ->writeFloat(1);
	Log::Get() << "Scale: (1, 1, 1)\n";
	}

	if (roll != NULL)
	{
	float rollVal;
	roll ->GetValue((*i), &rollVal, interval);

	fh ->writeFloat(rollVal);
	}
	else
	fh ->writeFloat(0.0f);
	}*/

	saver ->SaveAnimationStart();
	Control *pos = control ->GetPositionController();
	if (pos != NULL && IsTCBContol(pos))
	{
		IKeyControl *keyControl = GetKeyControlInterface(pos);

		int keysCount = keyControl ->GetNumKeys();

		if (keysCount > 0)
		{
			saver ->SavePositionBeginSection(keysCount);

			for (int i = 0; i < keysCount; i++)
			{
				ITCBPoint3Key key;
				keyControl ->GetKey(i, &key);

				saver ->SavePositionKey(TicksToSec(key.time) * 1000.0f, key.val.x, key.val.z, -key.val.y);
			}

			saver ->SavePositionEndSection();
		}
	}

	Control *rot = control ->GetRotationController();
	if (rot != NULL && IsTCBContol(rot))
	{
		IKeyControl *keyControl = GetKeyControlInterface(rot);

		int keysCount = keyControl ->GetNumKeys();
		if (keysCount > 0)
		{
			saver ->SaveRotationBeginSection(keysCount);

			Quat q;
			q.Identity();

			for (int i = 0; i < keysCount; i++)
			{
				ITCBRotKey key;
				keyControl ->GetKey(i, &key);

				Quat lq(key.val);
				q = q * lq;
				AngAxis angAxis(q);

				saver ->SaveRotationKey(TicksToSec(key.time) * 1000.0f, -angAxis.angle, angAxis.axis.x, angAxis.axis.z, -angAxis.axis.y);
			}

			saver ->SaveRotationEndSection();
		}
	}

	Control *scale = control ->GetScaleController();
	if (scale != NULL && IsTCBContol(scale))
	{
		IKeyControl *keyControl = GetKeyControlInterface(scale);

		int keysCount = keyControl ->GetNumKeys();
		if (keysCount > 0)
		{
			saver ->SaveScaleBeginSection(keysCount);

			for (int i = 0; i < keysCount; i++)
			{
				ITCBScaleKey key;
				keyControl ->GetKey(i, &key);

				saver ->SaveScaleKey(TicksToSec(key.time) * 1000.0f, key.val.s.x, key.val.s.y, key.val.s.z);
			}

			saver ->SaveScaleEndSection();
		}
	}

	Control *roll = control ->GetRollController();
	if (roll != NULL && IsTCBContol(roll))
	{
		IKeyControl *keyControl = GetKeyControlInterface(roll);

		int keysCount = keyControl ->GetNumKeys();
		if (keysCount > 0)
		{
			saver ->SaveRollBeginSection(keysCount);

			for (int i = 0; i < keysCount; i++)
			{
				ITCBFloatKey key;
				keyControl ->GetKey(i, &key);
				
				saver ->SaveRollKey(TicksToSec(key.time) * 1000.0f, key.val);
			}

			saver ->SaveRollEndSection();
		}
	}

	//end of animation signature
	saver ->SaveAnimationEnd();
}

void SGMExporter::ExportNode(IGameNode *igame_node, ISaver *saver)
{
	saver ->SaveStartNode(igame_node ->GetNodeID());

	INode *node = igame_node ->GetMaxNode();

	GMatrix nodeTM;

	nodeTM = igame_node ->GetLocalTM();
	saver ->SaveLocalTransformMatrix((float*)nodeTM.GetAddr());
	nodeTM = nodeTM.Inverse();
	saver ->SaveInverseLocalTransformMatrix((float*)nodeTM.GetAddr());

	nodeTM = igame_node ->GetObjectTM();
	saver ->SaveObjectTransformMatrix((float*)nodeTM.GetAddr());
	nodeTM = nodeTM.Inverse();
	saver ->SaveInverseObjectTransformMatrix((float*)nodeTM.GetAddr());

	nodeTM = igame_node ->GetWorldTM();
	saver ->SaveWorldTransformMatrix((float*)nodeTM.GetAddr());
	nodeTM = nodeTM.Inverse();
	saver ->SaveInverseWorldTransformMatrix((float*)nodeTM.GetAddr());

	Point3 pivotPoint = nodeTM.Translation();
	saver ->SavePivotPoint(pivotPoint.x, pivotPoint.y, pivotPoint.z);

	Control *control = node ->GetTMController();

	if (control ->IsAnimated())
	{
		saver ->SaveAnimationPresent();

		bool hasPos;
		bool hasRot;
		bool hasScale;
		ExportAnimation(control, saver, hasPos, hasRot, hasScale);
	}
	else
	{
		saver ->SaveAnimationNotPresent();
	}

	int node_childs_count = igame_node ->GetChildCount();

	if (node_childs_count > 0)
	{
		saver ->SaveStartNodes(node_childs_count);

		for (int i = 0; i < node_childs_count; i++)
			ExportNode(igame_node ->GetNodeChild(i), saver);

		saver ->SaveEndNodes();
	}

	StepProgress();

	saver ->SaveEndNode();
}

void SGMExporter::ExportObjects(IGameScene *igame_scene, ISaver *saver)
{
	int totalNodeCount = igame_scene ->GetTotalNodeCount();
	SetProgressSteps(totalNodeCount);

	int c_top_nodes = igame_scene ->GetTopLevelNodeCount();

	saver ->SaveStartNodes(c_top_nodes);

	for (int i = 0; i < c_top_nodes; i++)
		ExportNode(igame_scene ->GetTopLevelNode(i), saver);

	saver ->SaveEndNodes();
}

void SGMExporter::ExportScene(ISaver *saver)
{
	IGameScene *igame_scene = GetIGameInterface();
	IGameConversionManager *cm = GetConversionManager();
	cm ->SetCoordSystem(IGameConversionManager::IGAME_OGL);

	igame_scene ->InitialiseIGame(false);
	igame_scene ->SetStaticFrame(0);

	ExportObjects(igame_scene, saver);

	igame_scene ->ReleaseIGame();
}

bool SGMExporter::DoExport(const TCHAR *name, ExpInterface *ei, Interface *max_interface)
{
	std::ofstream xmlFile("c:\\animation.xml");
	ISaver *s = new XmlSaver(xmlFile);
	ExportScene(s);
	xmlFile.close();

	std::ofstream aniFile(name, std::ios::binary);
	ISaver *s2 = new AniSaver(aniFile);
	ExportScene(s2);
	aniFile.close();

	return true;
}

void SGMExporter::RegisterObserver(IProgressObserver *observer)
{
	observers.push_back(observer);
}

void SGMExporter::UnregisterObserver(IProgressObserver *observer)
{
	//TODO:
}

void SGMExporter::SetProgressSteps(int progressSteps)
{
	std::vector<IProgressObserver*>::iterator i;
	for (i = observers.begin(); i != observers.end(); i++)
		(*i) ->SetProgressSteps(this, progressSteps);
}

void SGMExporter::StepProgress()
{
	std::vector<IProgressObserver*>::iterator i;
	for (i = observers.begin(); i != observers.end(); i++)
		(*i) ->StepProgress(this);
}

const char *SGMExporter::GetResultMessage()
{
	return "";
}